﻿// (c) Copyright Microso Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved
// Developer:  Michael Antonio
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Xml;
using System.IO;
using System.Text;
using System.Xml.Linq;

namespace MichMan.Utilities
{
    public static class DataContractUtility
    {
        public static bool IsDataContractType(this Type t)
        {
            return t.GetCustomAttributes(typeof(DataContractAttribute), true).Any() ||
                t.GetCustomAttributes(typeof(CollectionDataContractAttribute), true).Any();
        }

        public static T ReadDataContract<T>(Stream stream) where T : class
        {
            using (XmlReader reader = XmlReader.Create(stream))
            {
                return ReadDataContract<T>(reader);
            }
        }

        public static T ReadDataContract<T>(XmlReader xmlReader) where T : class
        {
            if (!IsDataContractType(typeof(T)))
            {
                return null;
            }

            return ReadDataContract(xmlReader, typeof(T)) as T;
        }

        public static object ReadDataContract(Stream stream, Type t)
        {
            using (XmlReader reader = XmlReader.Create(stream))
            {
                return ReadDataContract(reader, t);
            }
        }

        public static object ReadDataContract(XmlReader xmlReader, Type t)
        {
            DataContractSerializer dataContractSerializer = new DataContractSerializer(t);
            object response = dataContractSerializer.ReadObject(xmlReader, true);
            xmlReader.Close();

            return response;
        }

        public static void WriteDataContract<T>(Stream stream, T data) where T : class
        {
            if (IsDataContractType(typeof(T)))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                serializer.WriteObject(stream, data);
            }
        }

        public static string DataContractToString<T>(T data) where T : class
        {
            if (IsDataContractType(typeof(T)))
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    WriteDataContract(ms, data);
                    byte[] blob = ms.ToArray();
                    return Encoding.UTF8.GetString(blob, 0, blob.Length);
                }
            }
            return null;
        }

        public static XElement DataContractToXElement(object obj)
        {
            if (obj == null)
            {
                return null;
            }

            DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
            using (MemoryStream memStream = new MemoryStream())
            {
                serializer.WriteObject(memStream, obj);
                memStream.Flush();
                memStream.Seek(0, SeekOrigin.Begin);

                return XElement.Load(memStream, LoadOptions.None);
            }
        }

        public static TEntity XElementToDataContract<TEntity>(XElement inputObject)
            where TEntity : class
        {
            return XElementToDataContract(inputObject, typeof(TEntity)) as TEntity;
        }

        public static object XElementToDataContract(XElement inputObject, Type type)
        {
            if (type == typeof(XElement))
            {
                // Return a new object.
                return XElement.Parse(inputObject.ToString());
            }

            if (inputObject == null)
            {
                return null;
            }

            object result = null;

            DataContractSerializer serializer = new DataContractSerializer(type);

            using (MemoryStream memStream = new MemoryStream())
            {
                inputObject.Save(memStream);
                memStream.Flush();
                memStream.Seek(0, SeekOrigin.Begin);

                result = serializer.ReadObject(memStream);
            }

            return result;
        }
    }
}